#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <functional>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/TcpClient.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/base/CountDownLatch.h>

class dictclient
{
public:
    dictclient()
        // 这里直接获取EventThreadLoop的指针给EventLoop对象
        :_loop(_loopthread.startLoop())     // loophtread 开始创建了对象之后 就可以自己在线程中自己循环监控数据
        , _client(_loop, muduo::net::InetAddress("127.0.0.1", 9090), "dictclient")
        ,_downlatch(1)   // 这里的count我们设置为一， 如果连接上就给count--，直接唤醒wait操作，让客户端来进行通信
    {
        // 设置这两个必须设置的函数对象
        _client.setConnectionCallback(std::bind(&dictclient::connCallBack, this, std::placeholders::_1));
        _client.setMessageCallback(std::bind(&dictclient::mesCallBack, this, std::placeholders::_1, 
            std::placeholders::_2, std::placeholders::_3));
        _client.connect();  // 这里只是发起了客户端连接服务端的操作
        _downlatch.wait();  // 用CountDownLatch的类来对客户端进行保护阻塞操作
    }

    bool send(const std::string& mes)
    {
        if(_conn->connected())
        {
            // 连接建立成功 可以发送消息
            _conn->send(mes);
            return true;
        }

        return false;
    }

    ~dictclient() {}
private:
    void connCallBack(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            std::cout << "连接成功!" << std::endl;
            _conn = conn;     // 把这个conn给到自己
            _downlatch.countDown();  // 让计数器减减 唤醒阻塞client
        }
        else
        {
            std::cout << "连接失败!" << std::endl;
            _conn.reset();   // 释放这个指针指向的空间
        }
    }

    void mesCallBack(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp timestamp)
    {
        // 取出来buf里面的数据 进行查询
        std::string str = buf->retrieveAllAsString();
        std::cout << str << std::endl;
    }

private:    
    muduo::net::TcpConnectionPtr _conn;  // 因为客户端无法自己访问连接完毕之后创建的TcpConnection对象，所以在此我们进行手动设置一个这个对象
    muduo::CountDownLatch _downlatch;
    muduo::net::EventLoopThread _loopthread;
    muduo::net::EventLoop* _loop;
    muduo::net::TcpClient _client;
};

int main()
{
    dictclient client;
    while(true)
    {
        std::string mes;
        std::cin >> mes;
        client.send(mes);
    }
    return 0;
}